package com.gitee.l0km.aocache;

import static com.gitee.l0km.aocache.AocacheUtils.invokeConstructor;
import static com.gitee.l0km.aocache.AocacheUtils.nonnullTypesOf;
import static com.gitee.l0km.aocache.AocacheUtils.EMPTY_CLASS_PARAMETERS;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

import java.util.concurrent.TimeUnit;

import com.gitee.l0km.aocache.annotations.AoCacheable;
import com.gitee.l0km.aocache.annotations.AoWeakCacheable;
import com.google.common.base.Throwables;

/**
 * 单实例缓存支持类，提供基于Guava缓存的单例对象管理功能。
 * 
 * <p>本类提供两种缓存方式：
 * <ul>
 *   <li>强引用缓存 - 通过@AoCacheable注解标记，缓存对象会一直存在直到被显式清除</li>
 *   <li>弱引用缓存 - 通过@AoWeakCacheable注解标记，缓存对象在没有强引用时会被JVM自动回收</li>
 * </ul>
 * 
 * <p>所有方法都是线程安全的，可以安全地在多线程环境下使用。
 * 
 * @author guyadong
 */
public class Singleton {

	/**
	 * [反射]创建新实例 
	 * @param <T>
	 * @param clazz
	 * @param parameterTypes 构造方法参数类型数组
	 * @param args 构造方法参数对象数组
	 */
	public static <T> T newInstance(Class<T>clazz,Class<?>[] parameterTypes, Object[]args)  {
		try {
			parameterTypes = null==parameterTypes
					? nonnullTypesOf(args) 
					: nonnullTypesOf(parameterTypes);
			args = (args == null) ? EMPTY_CLASS_PARAMETERS : args;
			checkArgument(parameterTypes.length == args.length,"MISMATCH parameterTypes.length and args.length");
			return (T) invokeConstructor(checkNotNull(clazz,"clazz is null"),args, parameterTypes);
		} catch (Exception e) {
			Throwables.throwIfUnchecked(e);
			throw new RuntimeException(e);
		} 
	}
	/**
	 * 参见 {@link #newInstance(Class, Class[], Object[])},
	 * {@code args}数组不允许有{@code null}元素，
	 * 否则会因为无法获取参数类型抛出异常
	 */
	public static <T> T newInstance(Class<T>clazz,Object... args)  {
		return newInstance(clazz,null,args);
	}
	/**
	 * 返回全局单实例[弱引用缓存]<br>
	 * 弱引用存储的实例在没有被引用时会被JVM自动回收，下次调用自动创建新实例 
	 * @param <T> 实例类型变量
	 * @param clazz 实例类型
	 * @param parameterTypes 构造方法参数类型数组
	 * @param args 构造方法参数对象数组
	 */
	@AoWeakCacheable(maximumSize = 200, expireAfterAccess = 20, expireAfterAccessTimeUnit = TimeUnit.SECONDS)
	public static <T> T weakSingletonOf(Class<T>clazz,Class<?>[] parameterTypes,Object[]args)  {
		return newInstance(clazz,parameterTypes,args);
	}
	/**
	 * 返回全局单实例[弱引用缓存] <br>
	 * 弱引用存储的实例在没有被引用时会被JVM自动回收，下次调用自动创建新实例 
	 * @param <T> 实例类型变量
	 * @param clazz 实例类型
	 * @param args 构造方法参数,不允许有{@code null}元素,否则会因为无法获取参数类型抛出异常
	 */
	@AoWeakCacheable(maximumSize = 200, expireAfterAccess = 20, expireAfterAccessTimeUnit = TimeUnit.SECONDS)
	public static <T> T weakSingletonOf(Class<T>clazz,Object...args)  {
		return newInstance(clazz,args);
	}
	/**
	 * 返回全局单实例[缓存]<br>
	 * 运行时对给定输入参数返回同一实例
	 * @param <T> 实例类型变量
	 * @param clazz 实例类型
	 * @param parameterTypes 构造方法参数类型数组
	 * @param args 构造方法参数对象数组
	 */
	@AoCacheable
	public static <T> T singletonOf(Class<T>clazz,Class<?>[] parameterTypes,Object[]args)  {
		return newInstance(clazz, parameterTypes, args);
	}
	/**
	 * 返回全局单实例[缓存]<br>
	 * 运行时对给定输入参数返回同一实例
	 * @param <T> 实例类型变量
	 * @param clazz 实例类型
	 * @param args 构造方法参数,不允许有{@code null}元素,否则会因为无法获取参数类型抛出异常
	 */
	@AoCacheable
	public static <T> T singletonOf(Class<T>clazz,Object...args)  {
		return newInstance(clazz, args);
	}
}
